using System;
using System.Collections.Generic;
using System.Text;
using Juego.Puente;
using Juego;
using System.Windows.Forms;
using PuenteInterfase;
using System.Diagnostics;
using System.Threading;
using System.ComponentModel;
using System.Linq;
using Juego.Vista;
using Vista;

namespace Juego.Controlador
{
    public class ControladorJuego2
    {

        public bool estaEnEjecucion;
        public double IntervaloSimulacion; 
        public ISuperficieDeDibujo superficieDeDibujo;
        private IList<IObjetoVivo> objetosVivos;
        private IList<IDibujable> dibujables;

        private Juego _juego;
        private IList<BloqueaTocar> _listaBloquesEnJuego;
        private Queue<BloqueaTocar> _bloquesPorLlegar;
        private double _tiempocero;
        private IList<BloqueaTocar> _bloquesABorrar;
        private IDictionary<int, BloqueaTocar> _bloqueslocos;


        public ControladorJuego2(ISuperficieDeDibujo superficieDeDibujo, Juego eljuego)
        {
            this.superficieDeDibujo = superficieDeDibujo;
            this.estaEnEjecucion = false;
            this.IntervaloSimulacion = 2000;
            this.objetosVivos = new List<IObjetoVivo>();
            this.dibujables= new List<IDibujable>();
            this._juego = eljuego;

        }


        public void ComenzarJuego()
        {
            BackgroundWorker delayer = new BackgroundWorker();

            delayer.DoWork += new DoWorkEventHandler(delayer_DoWork);
            delayer.RunWorkerAsync();

        }

        void delayer_DoWork(object sender, DoWorkEventArgs e)
        {
            ComenzarAsync();
        }

        public void ComenzarAsync()
        {
            estaEnEjecucion = true;

            _bloquesABorrar = new List<BloqueaTocar>();
            _tiempocero = AhoraEnSegundos();
            _listaBloquesEnJuego = new List<BloqueaTocar>();
            _bloquesPorLlegar = this._juego.BloquesPorLlegar;
            _bloqueslocos = new Dictionary<int, BloqueaTocar>();

            while (estaEnEjecucion)
            {
                Simular();
                Dibujar();
                Thread.Sleep(TimeSpan.FromMilliseconds(this.IntervaloSimulacion));
            }
        }

        public void DetenerJuego()
        {
            this.estaEnEjecucion = false;
        }

        public void agregarObjetoVivo(IObjetoVivo objetoVivo)
        {
            objetosVivos.Add(objetoVivo);
        }

        public void removerObjetoVivo(IObjetoVivo objetoVivo)
        {
            objetosVivos.Remove(objetoVivo);
        }

        public void agregarDibujable(IDibujable unDibujable)
        {
            dibujables.Add(unDibujable);
        }

        public void removerDibujable(IDibujable unDibujable)
        {
            dibujables.Remove(unDibujable);
        }

        private void Dibujar()
        {
            foreach (IDibujable dibujable in this.dibujables)
            {
                dibujable.Dibujar(this.superficieDeDibujo);
            }
            this.superficieDeDibujo.Actualizar();
        }

        private double AhoraEnSegundos()
        {
            return (System.DateTime.Now.TimeOfDay.TotalMilliseconds);
        }

        public bool QuedanBloquesEnJuego
        {
            get { return this._listaBloquesEnJuego.Count > 0; }
        }

        public IList<BloqueaTocar> BloquesEnJuego
        {
            get { return this._listaBloquesEnJuego; }
        }

        public IDictionary<int, BloqueaTocar> BloquesVisibles
        {
            get { return this._bloqueslocos; }
        }

        /**
         * Ejecuta la simulacion recorriendo la coleccion de objetivos vivos.
         */
        private void Simular()
        {
            this.superficieDeDibujo.Limpiar();

            if (this.QuedanBloquesEnJuego || _bloquesPorLlegar.Count > 0)
            {

                double justoAhora = this.AhoraEnSegundos();

                if (_bloquesPorLlegar.Count > 0)
                {
                    BloqueaTocar b = _bloquesPorLlegar.Peek();

                    if (((b.TiempoASerLanzado * 1000) + _tiempocero) < justoAhora)
                    {
                        BloqueaTocar bloque = _bloquesPorLlegar.Dequeue();
                        bloque.MomentoFueSoltado = (bloque.TiempoASerLanzado * 1000) + _tiempocero;
                        Debug.WriteLine("Desencole " + b.TiempoASerLanzado.ToString() + " + " + _tiempocero.ToString() + "<" + justoAhora.ToString());

                        _bloqueslocos.Add(bloque.Id, bloque);

                        _listaBloquesEnJuego.Add(bloque);
                        
                        this.agregarDibujable(new VistaBloqueaTocar(bloque));
                        this.agregarObjetoVivo(bloque);
                    }

                }
                /*
                IEnumerator<BloqueaTocar> iteradorBloquesEnJuego = _listaBloquesEnJuego.GetEnumerator();

                while (iteradorBloquesEnJuego.MoveNext())
                {
                    // calcular cuan "abajo" esta
                    double t = justoAhora - iteradorBloquesEnJuego.Current.MomentoFueSoltado;
                    double v = 100;

                    iteradorBloquesEnJuego.Current.PosicionY = (t * v) / 1000;
                    _bloqueslocos[iteradorBloquesEnJuego.Current.Id].PosicionY = (t * v) / 1000;

                    AlMoverseUnBloque(iteradorBloquesEnJuego.Current);

                    if (iteradorBloquesEnJuego.Current.PosicionY > 250)
                        _bloquesABorrar.Add(iteradorBloquesEnJuego.Current);


                    //Debug.WriteLine("el bloque esta en la posicion " + bloque.PosicionY);
                }
                iteradorBloquesEnJuego.Dispose();
                */
        
            }

            foreach (IObjetoVivo objetoVivo in this.objetosVivos)
            {
                if (objetoVivo.Vivo)
                    objetoVivo.Vivir();
                else
                {
                    this.removerObjetoVivo(objetoVivo);
                    
                }
            }
        }
    }
}
